/*
异步日志器缓冲区的实现：
    1. 向缓冲区写入数据
    2. 获取可读数据起始地址 -- 也就是从缓冲区的读取操作
    3. 获取可读数据的长度
    4. 移动读写位置
    5. 初始化缓冲区(也就是将读写指针设为0，当交换缓冲区之后，需要初始化缓冲区)
    6. 交换缓冲区的操作
*/

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cassert>

#ifndef __M_BUFFER_H__
#define __M_BUFFER_H__

namespace LogModule
{
#define DEFAULT_BUFFER_SIZE (1024)   // 缓冲区默认大小  // 而我修改这里，就是为了保证这个缓冲区小，打满之后就等待了
#define THRESHOLD_BUFFER_SIZE (8 * 1024 * 1024) // 在该范围内，指数扩容
#define INCREMENT_BUFFER_SIZE (1 * 1024 * 1024) // 线性扩容，一次扩容容量

    class Buffer
    {
    public:
        Buffer() : _buffer(DEFAULT_BUFFER_SIZE), _writer_idx(0), _reader_idx(0) {}
        // 向缓冲区中写入数据
        void Push(const char *data, size_t len)
        {
            // 1. 写入前，要判断缓冲区中是否有足够的位置进行写入，如果没有位置
            // 两种策略： 1. 阻塞等待   2. 扩容(实际开发不需要，只用于测试)
            EnsureEnoughSize(len); // 这里不关心是否需要扩容，尽管扩容，异步工作器关心是否扩容
            // 2. 有空间，直接写入
            std::copy(data, data + len, &_buffer[_writer_idx]);
            // 3. 写入之后，需要移动write指针
            MoveWriter(len);
        }
        // 获取可读数据的起始地址 -- 也就是从缓冲区的读取操作
        const char *Begin()
        {
            return &_buffer[_reader_idx];
        }
        // 返回可读取的数据长度
        size_t ReadAbleSize()
        {
            return (_writer_idx - _reader_idx);
        }
        // 返回可写入的数据长度
        size_t WriteAbleSize()
        {
            return (_buffer.size() - _writer_idx);
        }
        // 移动读位置
        void MoveReader(size_t len)
        {
            // 如果想要移动读指针比可读数据还长，就错误了
            assert(len <= ReadAbleSize());
            _reader_idx += len;
        }
        // 重置读写位置，初始化缓冲区
        void Reset()
        {
            _writer_idx = 0;
            _reader_idx = 0;
        }
        // 缓冲区的交换
        void Swap(Buffer &buffer)
        {
            _buffer.swap(buffer._buffer);
            std::swap(_reader_idx, buffer._reader_idx);
            std::swap(_writer_idx, buffer._writer_idx);
        }
        // 判断缓冲区是否为空
        bool Empty()
        {
            return (_writer_idx == _reader_idx);
        }

    private:
        // 为测试提供一个扩容操作 -- 实际开发不会进行扩容
        void EnsureEnoughSize(size_t len)
        {
            if(len <= WriteAbleSize()) return;
            // 扩容思路：在一个范围内，指数扩容。超出范围后，线性扩容
            size_t new_size = 0;
            if (_buffer.size() + len < THRESHOLD_BUFFER_SIZE)
                new_size = _buffer.size() * 2 + len;
            else
                new_size = _buffer.size() + INCREMENT_BUFFER_SIZE + len;
            _buffer.resize(new_size);
        }
        // 移动写位置 -- 外界不需要
        void MoveWriter(size_t len)
        {
            assert((len + _writer_idx) <= _buffer.size());
            _writer_idx += len;
        }

    private:
        std::vector<char> _buffer;
        size_t _writer_idx; // 当前写入位置的指针
        size_t _reader_idx; // 当前读取位置的指针
    };
}

#endif